package Comunication;

import java.util.LinkedList;
import java.util.List;

public class P implements Runnable {
	private Use u;
	private int id;
	private int bloksNumber;
	private List<Block> blocksList;
	
	public P(Use u, int id, int bn) {
		this.u = u;
		this.bloksNumber = bn;
		this.id = id;
		blocksList = new LinkedList<Block>();
		for (int i = 0; i < bloksNumber; i++) {
			blocksList.add(new Block(2, "1" + i + "0", "0000"));
		}

		new Thread(this, "ThreadP" + id).start();
	}

	private boolean hasAddress(final String address) {
		for (Block b : blocksList) {
			if (b.tag == address) {
				return true;
			}
		}
		return false;
	}
	
	public int getDirectMappedBlock(String address, int startIndex) {
		String bin = Integer.toBinaryString(Integer.parseInt(address,16));
		return Integer.parseInt(bin.substring(bin.length()-startIndex, bin.length()-3),2);
	}

	/*public int getAssociativeBlock(String address, int startIndex) {
		
	}*/
	
	public int getSetAssociativeBlock(String address, int startIndex, int nBlock) {
		String bin = Integer.toBinaryString(Integer.parseInt(address,16));
		int n= Integer.parseInt(bin.substring(bin.length()-startIndex, bin.length()-3),2);
		n = (n % (nBlock/2))*2;
		if(blocksList.get(n).used==false)
			return n;
		else
			return n+1;
	}
	
	public void run() {
		Protocols prot = new Protocols();
		try {
			while (true) {
				Message m = u.extract(id);				
				if (m != null) {
					// check if i already red this message ??????
					// change 5 with the user inserted parameter
					Block myblock = blocksList.get(getDirectMappedBlock(m.address,5)); 
					// to get block check for cache type(associative/direct) ??????
					// check for block status. if it isn't invalid -> flush ??????
					int op = prot.getMsiOperation((myblock.state*10) + m.operation);
					switch(op){
					case 0:{
						// execute m.operation to update the cache
						// add m.operation in instruction list
						break;
					}
					// for each i from 1 to 6 
					// - add first the m.operation in instruction list
					// - execute the op(i) instruction (send in the bus)
					// - wait for data response
					// - update cache memory
					// - add op(i) in instruction list
					case 1:{	// PrRd
						break;
					}
					case 2:{	// PrWr
						break;
					}
					case 3:{	// BusRd
						break;
					}
					case 4:{	// BusRdX
						break;
					}
					case 5:{	// BusUpgr
						break;
					}
					case 6:{	// Flush
						break;
					}
					case 9:{	// No action
						break;
					}
					}

					int st = prot.getMsiState((myblock.state*10) + m.operation);
					switch(st){
					case 9:{	// No action
						break;
					}
					case 1:{	// M-status
						myblock.state = 1;
						break;
					}
					case 2:{	// S-status
						myblock.state = 2;
						break;
					}
					case 3:{	// I-status
						myblock.state = 3;
						break;
					}
					}
				}
			}
		} catch (Exception e) {
			System.out.println("Uscita " + Thread.currentThread().getName());
			e.printStackTrace();
		}
	}
}